Writing Python documentation

What's the goal of documenting code?

In [1]:
def T2rgb(Ts, fn='smj10q.csv', n=None, modw=None):
    ...
In [2]:
def Temp_to_rgb(temps, eye_response_fn='smj10q.csv', normed_at=None, modulate_with=None):
    """
    Converts an array of blackbody temperatures to RGB.
    
    Parameters
    ----------
    temps: numpy array
        The temperatures to convert
    eye_response_fn : str
        Path to the file with the human eye cone response functions
    normed_at: float or None
        The temperature at which the responses should be unity, or None to
        apply no rescaling of the response functions.
    modulate_with: numpy array or None
        A rescaling factor to multiply the output cones by, or None to do no
        rescaling of the output.
        
    Returns
    -------
    rgb : numpy array
        The output RGB values. Has shape (3, ... shape of ``temps`` ...)
    """
    ...

What's the goal of documenting code?

  • "Science" (or "dirty") mode
    • For future you
    • For reproducibility
    • For the poor grad student who might one day need to read your code
  • For your future self
  • For the poor grad student/postdoc who might one day need to read your code
  • Public/"Developer" mode
    • For others: to provide background
    • To get people to help you work on it

Lets talk about "Docstrings"

In [3]:
def square(val):
    return 4*val
In [4]:
def square(val):
    """
    The perimeter of a square with size ``val``.
    """
    return 4*val

Why is this A Good Thing™?

In [5]:
def square(val):
    """
    The perimeter of a square with size ``val``.
    """
    return 4*val
  • It lets you easily document anything in Python:
In [6]:
# In the notebook this will pop up a window with the docstring
square?
  • It lets you document as you write the code.
  • This means with realtively little discipline you might actually do it.
  • The docs are actually visible from the code:
In [7]:
print(square.__doc__)
    The perimeter of a square with size ``val``.
    

Which allows all kinds of magic.

Even with just docstrings you make big progress in readability!

Use them in every function you write, and put them at the top of a .py file, giving things like:

In [8]:
import astropy
print(astropy.__doc__)
Astropy is a package intended to contain core functionality and some
common tools needed for performing astronomy and astrophysics research with
Python. It also provides an index for other astronomy packages and tools for
managing them.

And there are other kinds of "documentation" that don't require a tool

  • A package/file layout that's thought-out
  • Code comments
  • Consistent code style
    • Recommended: PEP8
    • This will do wonders for your code's readability
    • (But bend the rules when it makes sense - otherwise'll make you crazy)

How can you take it one step further?

http://www.sphinx-doc.org/

  • Sphinx is a documentation generator
    • Meaning it takes a bunch of files describing your code and puts them together into a web site, PDF, TeX, etc.
  • It also has a bunch of extensions to do that to docstrings
  • The real power of Sphinx is that it combines these two: you can write both narrative docs and include docstrings.

How do you write Sphinx docs?

ReST (ReStructured Text)

Actually developed before Sphinx narrowly focused on Python docs

A good primer: http://www.sphinx-doc.org/en/1.5/rest.html

This ReST file

In [9]:
from IPython.core.display import display, Markdown

with open('rest_example.rst') as f:
    display(Markdown('```\n'+f.read()+'\n```'))
This is a paragraph.  It's quite
short.

   This paragraph will result in an indented block of
   text, typically used for quoting other text.

1. This is a numbered item
2. As is this

This is inline code: ``np.random.randn(100)``

And this is a block of code::

    a = np.random.randn(100)
    plt.plot(a)

And here's a nice image:

.. image:: astropylogo.png

Renders to:

In [10]:
from IPython.core.display import display, HTML

with open('rest_example.html') as f:
    display(HTML(f.read()))

This is a paragraph. It's quite short.

This paragraph will result in an indented block of text, typically used for quoting other text.
  1. This is a numbered item
  2. As is this

This is inline code: np.random.randn(100)

And this is a block of code:

a = np.random.randn(100)
plt.plot(a)

And here's a nice image:

astropylogo.png

How do you get sphinx working for your code?

  • Follow the Sphinx quick-start: http://www.sphinx-doc.org/en/1.5/tutorial.html
    • Straightforward to start with, lots of options
    • Requires choosing between those options, have to communicate structure to other contributors
    • Does not come with a straightforward/automatic "copy over my docstrings" tool
  • Use the Astropy affiliated package template (https://github.com/astropy/package-template)
    • Has very specific step-by-step instructions on how to get up and running
    • Follows a fairly standard layout, sphinx works out-of-the-box - just type python setup.py build_docs
    • All you have to do to get docstrings is ".. automodapi:: yourpkg"
    • Has an advanced(/complex) set of options for how to make your docstrings pretty, and an ecosystem (Astropy) with lots of copy-and-paste-able examples.
    • (Comes with lots of other stuff that's not documentation but might be useful for you)